#pragma once
#include <nice2d/predef.h>
#include <nice2d/entity.h>
#include <nice2d/util.h>

class ControlStyle : public Serializer
{
    DECLARE_OBJECT(ControlStyle)
public:
    ControlStyle();
    virtual ~ControlStyle();
public:;
    virtual PTree serialize()override;
    virtual void deserialize(const PTree &node)override;
    virtual void sync();
public:
    BackgroundPointer normalBackground;
    BackgroundPointer disableBackground;
    BackgroundPointer pressedBackground;
    BackgroundPointer hoverBackground;
};

using ControlStylePointer = std::shared_ptr<ControlStyle>;

class Control;
using ControlPointer = std::shared_ptr<Control>;

enum ControlResizeRule {
    ControlResizeRule_Fixed = 0,
    ControlResizeRule_Fill
};

BOOST_DESCRIBE_ENUM(ControlResizeRule,ControlResizeRule_Fixed,ControlResizeRule_Fill)

enum ControlUpdateFlag
{
    ControlUpdateFlag_Style = 0,
    ControlUpdateFlag_Max
};

class Control : public Entity
{
    DECLARE_OBJECT(Control)
    friend class ControlLayout;
    friend class Desktop;
public:
    Control(const sf::Vector2f &size = sf::Vector2f());
    virtual ~Control();
public:
    void setPadding(float padding);
    bool getPadding()const;

    void setWidth(float width);
    float getWidth()const;

    void setHeight(float heigh);
    float getHeight()const;
public:
    void setHResizeRule(ControlResizeRule rule);
    void setVResizeRule(ControlResizeRule rule);
    void setResizeRule(ControlResizeRule h,ControlResizeRule v);
    boost::signals2::signal<void(ControlResizeRule,ControlResizeRule)> resizeRuleChanged;

    ControlResizeRule getHResizeRule()const;
    ControlResizeRule getVResizeRule()const;
public:
    void setParent(std::weak_ptr<Control> parent);
    std::weak_ptr<Control> getParent()const;

    void setActive(bool active = true);
    bool isActive()const;
    boost::signals2::signal<void(bool)> activeChanged;

    void show();
    void hide();

    void setFocused(bool focus = true);
    bool isFocused()const;
    boost::signals2::signal<void(bool)> focusChanged;
public:
    virtual ControlPointer getControlBelow(const sf::Vector2i &point);
    virtual bool doesHierarchyContain(ControlPointer other)const;

    virtual void caculateSize();
public:
    void setControlStyle(ControlStylePointer style);
    ControlStylePointer getControlStyle()const;

    template<class Style>
    std::shared_ptr<Style> getTemplateStyle()const
    {
        return std::dynamic_pointer_cast<Style>(getControlStyle());
    }
protected:
    virtual void onPaddingChanged();

    virtual void onActiveChanged();
    virtual void onGainFocus();
    virtual void onLostFocus();

    virtual void onMouseEnter() override;
    virtual void onMouseExit() override;

    virtual void onPositionChanged() override;
    virtual void onSizeChanged() override;

    virtual void onStyleChanged();
protected:
    void onUpdateEntity(float deltaTime) override;
    void onDrawEntity(sf::RenderTarget &target, sf::RenderStates states)const override;

    virtual void onUpdateControl(float deltaTime);
    virtual void onDrawControl(sf::RenderTarget &target, sf::RenderStates states) const;
private:
    std::unique_ptr<class ControlData> data;
};
